﻿using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using Microsoft.Data.Sqlite;
using Super.Admin.Entities;
using Super.Admin.IServices;

namespace Super.Admin.Services
{
    /// <summary>
    /// 基础服务实现类
    /// </summary>
    public class BaseService : IBaseService
    {
        protected readonly DbContext Context;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="context">数据库上下文</param>
        public BaseService(DbContext context)
        {
            Context = context;
        }

        #region Query
        /// <summary>
        /// 根据id查询实体 主键查询
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns>实体</returns>
        public T Find<T>(params object?[]? keyValues) where T : class
        {
            return Context.Set<T>().Find(keyValues);
        }
        /// <summary>
        /// 提供对单表的查询
        /// </summary>
        /// <returns>IQueryable类型集合</returns>
        [Obsolete("尽量避免使用，using 带表达式目录树的 代替")]
        public IQueryable<T> Set<T>() where T : class
        {
            return Context.Set<T>();
        }
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="funcWhere">查询条件</param>
        /// <returns>IQueryable类型集合</returns>
        public IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class
        {
            return Context.Set<T>().Where(funcWhere);
        }
        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <typeparam name="S">排序的字段类型</typeparam>
        /// <param name="funcWhere">筛选方法</param>
        /// <param name="pageSize">一页的数量</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="funcOrderby">排序方法</param>
        /// <param name="isAsc">是否正序</param>
        /// <returns>分页查询结果</returns>
        public PageResult<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true, params Func<IQueryable<T>, IQueryable<T>>[] loadNavigations) where T : class
        {
            var query = Set<T>();
            if (funcWhere != null)
            {
                query = query.Where(funcWhere);
            }
            if (loadNavigations != null)
            {
                foreach (var loader in loadNavigations)
                {
                    query = loader(query);
                }
            }
            query = isAsc ? query.OrderBy(funcOrderby) : query.OrderByDescending(funcOrderby);
            int totalCount = query.Count();
            List<T> data = query.AsNoTracking().Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
            PageResult<T> result = new PageResult<T>()
            {
                DataList = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(),
                PageIndex = pageIndex,
                PageSize = pageSize,
                TotalCount = totalCount
            };
            return result;
        }
        #endregion

        #region Insert
        /// <summary>
        /// 新增数据，即时Commit
        /// </summary>
        /// <param name="t"></param>
        /// <returns>返回带主键的实体</returns>
        public T Insert<T>(T t) where T : class
        {
            try
            {
                Context.Set<T>().Add(t);
                //Commit();//写在这里  就不需要单独commit  不写就需要
                return t;
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        /// <summary>
        /// 新增数据，即时Commit
        /// 多条sql 一个连接，事务插入
        /// </summary>
        /// <param name="tList">插入的集合</param>
        public IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class
        {
            Context.Set<T>().AddRange(tList);
            //Commit();//一个链接  多个sql
            return tList;
        }
        #endregion

        #region Update
        /// <summary>
        /// 更新数据，即时Commit
        /// </summary>
        /// <param name="t">修改的实体</param>
        public void Update<T>(T t) where T : class
        {
            if (t == null) throw new ArgumentNullException(nameof(t));
            // 先分离可能冲突的实体
            var entry = Context.Entry(t);
            if (entry.State == EntityState.Detached)
            {
                // 查找已跟踪的相同实体
                var existing = Context.Set<T>().Local
                    .FirstOrDefault(e => Context.Entry(e).Properties
                        .Where(p => p.Metadata.IsPrimaryKey())
                        .Select(p => p.CurrentValue)
                        .SequenceEqual(
                            entry.Properties
                                .Where(p => p.Metadata.IsPrimaryKey())
                                .Select(p => p.CurrentValue)
                        ));

                if (existing != null)
                {
                    Context.Entry(existing).State = EntityState.Detached;
                }
            }
            entry.State = EntityState.Modified;
            //Commit();
        }
        /// <summary>
        /// 更新数据，即时Commit
        /// </summary>
        /// <param name="tList">修改的整体集合</param>
        public void Update<T>(IEnumerable<T> tList) where T : class
        {

            foreach (var t in tList)
            {
                //Context.Set<T>().Attach(t);
                //Context.Entry(t).State = EntityState.Modified;
                if (t == null) throw new ArgumentNullException(nameof(t));
                // 先分离可能冲突的实体
                var entry = Context.Entry(t);
                if (entry.State == EntityState.Detached)
                {
                    // 查找已跟踪的相同实体
                    var existing = Context.Set<T>().Local
                        .FirstOrDefault(e => Context.Entry(e).Properties
                            .Where(p => p.Metadata.IsPrimaryKey())
                            .Select(p => p.CurrentValue)
                            .SequenceEqual(
                                entry.Properties
                                    .Where(p => p.Metadata.IsPrimaryKey())
                                    .Select(p => p.CurrentValue)
                            ));

                    if (existing != null)
                    {
                        Context.Entry(existing).State = EntityState.Detached;
                    }
                }
                entry.State = EntityState.Modified;
            }
            //Commit();
        }

        #endregion

        #region Delete
        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="keyValues">删除主键</param>
        public void Delete<T>(params object?[]? keyValues) where T : class
        {
            T t = Find<T>(keyValues);
            if (t == null) throw new Exception("t is null");
            Context.Set<T>().Remove(t);
            //Commit();
        }
        /// <summary>
        /// 批量多主键删除
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <param name="keyValues">多主键</param>
        public void Deletes<T>(IEnumerable<object[]> keyValues) where T : class
        {
            foreach (object[] keyValue in keyValues)
            {
                T t = Find<T>(keyValue);
                if (t == null) throw new Exception("t is null");
                Context.Set<T>().Remove(t);
            }
            //Commit();
        }
        /// <summary>
        /// 批量单主键删除
        /// </summary>
        /// <typeparam name="T">实体</typeparam>
        /// <typeparam name="TId">删除的ID类型</typeparam>
        /// <param name="keyValues">主键</param>
        public void Deletes<T, TId>(IEnumerable<TId> keyValues) where T : class
        {
            foreach (var keyValue in keyValues)
            {
                T t = Find<T>(keyValue);
                if (t == null) throw new Exception("t is null");
                Context.Set<T>().Remove(t);
            }
            //Commit();
        }
        #endregion

        #region Other
        /// <summary>
        /// 立即保存全部修改
        /// 把增/删的savechange给放到这里，是为了保证事务的
        /// </summary>
        public void Commit()
        {
            Context.SaveChanges();
        }
        /// <summary>
        /// 执行sql 返回集合
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public IQueryable<T> ExcuteQuery<T>(string sql, SqliteParameter[] parameters) where T : class
        {
            return null;
        }
        /// <summary>
        /// 执行sql，无返回
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="parameters"></param>
        public void Excute<T>(string sql, SqliteParameter[] parameters) where T : class
        {
            IDbContextTransaction trans = null;
            try
            {
                trans = Context.Database.BeginTransaction(); //这里是启动一个事务
                //trans.Commit();
            }
            catch (Exception)
            {
                if (trans != null)
                    trans.Rollback();
                throw;
            }
        }
        /// <summary>
        /// 销毁
        /// </summary>
        public virtual void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
            }
        }
        #endregion
    }
}
